Ten dokument opisuje sposoby, możliwości i techniki porządkowania i czyszczenia danych z użyciem biblioteki (Pandas) i (Polars) python.
Mam nadzieję, że będzie to dla Ciebie przydatne! Miłej lektury!
Author
Piotr Dłubak
Published
February 18, 2025
Wprowadzenie
Analiza danych:
Badana populacja: Klienci sklepów spożywczych
Rodzaj badania: Ankieta on-line dostępna dla wszystkich użytkowników na terenie Polski
Metoda analizy: EDA (“Exploratory Data Analysis”) - analiza deskrypcyjna
Parametry badania:
Zmienne ilościowe:
wiek
liczba osób w rodzinie
dochody
wydatki
Zmienne jakościowe:
płeć
wykształcenie
preferowany typ sklepu
preferowana marka sklepu
preferowanay towar
czynnik zakupowy
rodzaj promocji
miasto
Wyniki przeprowadzonej analizy pokazały, że dla współczesnego konsumenta decyzja o zakupie produktu nie jest motywowana wyłącznie chęcią zaspokojenia określonych potrzeb, ale w znacznym stopniu determinuje ją potrzeba demonstracji przekonań, statusu społeczno-ekonomicznego i stylu życia. Nowoczesny model konsumpcji niesie określone konsekwencje dla praktyki działań marketingowych.
Badanie ankietowe dotyczyło postaw i zachowań respondentów w trakcie dokonywania zakupów produktów żywnościowych. W tym celu został skonstruowany kwestionariusz ankiety.
Cechy, takie jak wiek, płeć, wykształcenie, preferowany typ sklepu, dochody netto, preferowana marka sklepu, preferowany towar, preferowany rodzaj promocji oraz czynnik zakupowy, mogą wpływać na wysokość zakupów żywnościowych.
Wymagania dotyczące danych: Zdefiniowenie zakresu analizy (zmienne, obserwacje, zakresy dziedzinowe)
Preprocessing danych – co to jest i dlaczego jest ważny?
1. Czym jest preprocessing danych?
Preprocessing danych to zbiór technik i operacji stosowanych w celu przygotowania surowych danych do analizy, eksploracji czy modelowania. Obejmuje on czyszczenie, transformację i normalizację danych, aby poprawić ich jakość i ułatwić dalsze przetwarzanie.
2. Kluczowe etapy preprocessingu danych
Usuwanie brakujących wartości – wypełnianie braków metodami statystycznymi (np. średnia, mediana) lub usuwanie niekompletnych rekordów.
Obsługa wartości odstających – identyfikacja i eliminacja anomalii, które mogą zaburzać analizę.
Czyszczenie danych z błędów – poprawianie literówek, błędnych wpisów i formatowania danych.
Usuwanie duplikatów – eliminacja powtarzających się rekordów, które mogą fałszować wyniki analizy.
Wykrywanie i poprawa niezgodności danych – identyfikacja sprzecznych informacji (np. ujemny wiek, błędne daty) i ich korekta.
Standaryzacja i normalizacja – przekształcanie danych do jednolitej skali w celu poprawy wydajności modeli ML.
Kodowanie zmiennych kategorycznych – zamiana wartości tekstowych na wartości numeryczne (np. one-hot encoding, label encoding).
Usuwanie lub redukcja zmiennych – eliminacja kolinearnych lub nieistotnych cech, co zwiększa efektywność analizy.
Tworzenie cech (feature engineering) – generowanie nowych zmiennych, które lepiej reprezentują dane.
Redukcja wymiarowości – stosowanie technik takich jak PCA w celu zmniejszenia liczby zmiennych wejściowych.
Dekompozycja danych czasowych – wydzielanie sezonowości, trendów i anomalii w szeregach czasowych.
3. Dlaczego preprocessing danych jest ważny?
Poprawa jakości danych – usuwa błędy, brakujące wartości i anomalia, co zapobiega błędnym wnioskom.
Zwiększenie wydajności modeli ML – dobrze przygotowane dane poprawiają skuteczność algorytmów uczenia maszynowego.
Redukcja szumu – minimalizuje wpływ nieistotnych lub błędnych informacji.
Lepsza interpretacja wyników – przejrzyste i dobrze przygotowane dane ułatwiają analizę i wyciąganie wniosków.
Efektywność obliczeniowa – optymalizacja struktury danych zmniejsza czas i zasoby potrzebne do analizy.
Dobrze wykonany preprocessing jest kluczowym etapem analizy danych i ma bezpośredni wpływ na jakość oraz dokładność wyników! 🚀
“Co to jest analiza EDA?”
Analiza deskrypcyjna to proces badania, opisywania i interpretacji danych w celu uzyskania wglądu i zrozumienia ich cech, wzorców i związków. Jest to technika często stosowana w dziedzinach naukowych, badań społecznych, statystyce, lingwistyce i wielu innych dziedzinach. Głównym celem analizy deskrypcyjnej jest opisanie i podsumowanie danych w sposób, który ujawnia istotne informacje. Może obejmować takie elementy jak obliczanie średnich, median, odchyleń standardowych, minimalnych i maksymalnych wartości, oraz prezentowanie danych w postaci tabel, wykresów lub grafów.
Analiza deskrypcyjna umożliwia identyfikację kluczowych cech, trendów, anomalii i relacji w danych. Może również pomóc w odkrywaniu wzorców, porównywaniu grup lub kategorii danych oraz wyprowadzaniu wniosków na podstawie zebranych informacji. Głównym celem EDA jest zapewnienie wglądu w dane jeszcze przed sformułowaniem jakichkolwiek założeń. Pomaga identyfikować oczywiste błędy, lepiej pojmować wzorce występujące w obrębie danych, wykrywać wartości odstające i anomalie, a także odnajdywać interesujące relacje między zmiennymi. Po przeprowadzeniu analizy EDA i uzyskaniu istotnych spostrzeżeń wciąż można wykorzystać tę metodę do bardziej zaawansowanej analizy danych lub modelowania, w tym na potrzeby uczenia maszynowego.
flowchart LR
A{Preprocesing danych} --> B(Pozyskanie danych)
A --> C(Porządkowanie danych)
A --> D(Czyszczenie danych)
B --> E[Źródła danych]
B --> F[Pobieranie danych]
Źródła danych
Dane można pozyskiwać z różnych źródeł w zależności od celu analizy: a) Dane publiczne i otwarte
Bazy danych rządowe – np. Eurostat, GUS, UCI Machine Learning Repository, Open Data Portal.
Dane naukowe – Kaggle Datasets, Google Dataset Search.
APIs – np. Twitter API, OpenWeatherMap, Google Maps API.
Wewnętrzne źródła danych
Bazy relacyjne (SQL, NoSQL) – np. PostgreSQL, MongoDB. Dane logów i telemetryczne – np. pliki JSON, Parquet, Apache Kafka. Dane biznesowe – CRM, ERP, systemy księgowe.
Dane generowane przez użytkowników
Ankiety i formularze – Google Forms, SurveyMonkey. Social media – Facebook Graph API, YouTube API. Systemy IoT – sensory, urządzenia smart.]
Pobieranie danych
Dane można pobierać na kilka sposobów: a) Pobieranie ręczne
Pobranie plików CSV, Excel, JSON, XML.
Eksport z baz danych.
Web Scraping
Biblioteki Python: BeautifulSoup, Scrapy, Selenium. API REST: requests, urllib.
Automatyczna ekstrakcja i strumieniowanie danych
Apache Kafka, Spark Streaming – do przetwarzania danych w czasie rzeczywistym. ETL (Extract, Transform, Load) – np. Airflow, Talend, dbt.
I. Wstępne przetwarzanie
1. Przygotowanie danych
1.1. Pozyskanie danych
Dane pozyskano z przeprowadzonego badania ankietowego, które dotyczyło postaw i zachowań respondentów w trakcie dokonywania zakupów produktów żywnościowych. W tym celu został skonstruowany kwestionariusz ankiety. Dane ankietowe zostały zebrane w formie plików, które następnie załadowano do analizy. Pliki te zawierają informacje o respondentach, takie jak wiek, płeć, wykształcenie, preferencje zakupowe oraz czynniki wpływające na decyzje zakupowe.
Szczegółowe dane zostały zapisane w następujących plikach:
ankieta_01a.xlsx
ankieta_01b.xlsx
ankieta_02.csv
miasta.json
1.2. Pobranie i załadowanie danych
Dane te zostały załadowane do odpowiednich DataFrame’ów:
Plik
DataFrame
Opis
ankieta_01a.xlsx
ankieta_01a
Zawiera podstawowe informacje o respondentach.
ankieta_01b.xlsx
ankieta_01b
Zawiera dodatkowe informacje o respondentach.
ankieta_02.csv
ankieta_02
Zawiera dane dotyczące dochodów i wydatków respondentów.
miasta.json
miasta
Zawiera informacje o miastach, z których pochodzą respondenci.
1.3. Podgląd tabel
Code
import warningsimport pandas as pdimport numpy as npimport seaborn as snsimport matplotlib.pyplot as pltimport statsmodels.api as smimport randomfrom scipy.stats import zscoreimport reimport mathwarnings.filterwarnings("ignore")from IPython.display import display, Markdownimport polars as plankieta_01a = pd.read_excel('ankieta_01a.xlsx')ankieta_01b = pd.read_excel('ankieta_01b.xlsx')ankieta_02 = pd.read_csv('ankieta_02.csv', skiprows=1, skipfooter=1, delimiter=';',engine='python')miasta = pd.read_json('miasta.json')def display_table_info(tables): info = []for name, df in tables.items(): info.append({'Nazwa': name,'Liczba kolumn': df.shape[1],'Liczba wierszy': df.shape[0] })return pd.DataFrame(info)tables = {'ankieta_01a': ankieta_01a,'ankieta_01b': ankieta_01b,'ankieta_02': ankieta_02,'miasta': miasta}def unique_values_summary(tables): summary = []for table_name, df in tables.items():for col in df.columns: unique_values = df[col].unique() summary.append({'Nazwa tabeli': table_name,'Nazwa kolumny': col,'Liczba unikatowych wartości': len(unique_values),'Lista unikatowych wartości': unique_values })return pd.DataFrame(summary)unique_summary_df = unique_values_summary(tables)display(unique_summary_df)table_info = display_table_info(tables)display(table_info)def display_dataframe_with_title(df, title): display(Markdown(f"#### {title}")) display(df.head())print()#display(Markdown("**WYŚWIETLENIE ZAWARTOŚCI TABEL - 5 pierwszych wierszy**"))print()display_dataframe_with_title(ankieta_01a, "Tabela: ankieta_01a")display_dataframe_with_title(ankieta_01b, "Tabela: ankieta_01b")display_dataframe_with_title(ankieta_02, "Tabela: ankieta_02")display_dataframe_with_title(miasta, "Tabela: miasta")
Nazwa tabeli
Nazwa kolumny
Liczba unikatowych wartości
Lista unikatowych wartości
0
ankieta_01a
id.
59
[R_001, R_002, R_003, R_004, R_005, R_006, R_0...
1
ankieta_01a
kod_miasta
39
[M_058, M_050, M_069, M_059, M_057, M_001, M_0...
2
ankieta_01a
wiek|liczba osób w rodzinie
52
[30|2, 16|1, 49|1, 67 lat|1, 38|5, 28|1, 158|5...
3
ankieta_01a
m_wykształcenie
7
[podstawowe, podstawowe., zawodowe, średn, śre...
4
ankieta_01a
k_wykształcenie
5
[nan, podstawowe, zawodowe, śred5nie, średnie]
5
ankieta_01a
PREFEROWANY TYP SKLEPU
4
[BAZAREK, OSIEDLOWY, SUPERMARKET, GALERIA]
6
ankieta_01a
preferowana marka sklepu
13
[POLOMARKET, NETTO, BIEDRONKA, LIDL, DINO, KAU...
7
ankieta_01a
preferowanay towar
7
[Napoje, Owoce i warzywa, Produkty piekarnicze...
8
ankieta_01a
preferowany rodzaj promocji
8
[sugestia, gazetka, reklama, karta, sms, email...
9
ankieta_01a
preferowany rodzaj promocji.1
4
[kasjera, nan, RTV, korzystam]
10
ankieta_01a
czynnik zakupowy
6
[cena, dostępność, jakość, marka, skład, lokal...
11
ankieta_01b
id.
66
[R_060, R_061, R_062, R_063, R_064, R_065, R_0...
12
ankieta_01b
kod_miasta
46
[M_048, M_014, M_062, M_053, M_041, M_059, M_0...
13
ankieta_01b
wiek|liczba osób w rodzinie
58
[58|2, 46|4, 16|4, 28|2, 55|5, 37|3, 35|1, 43|...
14
ankieta_01b
m_wykształcenie
1
[nan]
15
ankieta_01b
k_wykształcenie
5
[średnie, ś, wyższe, w, wyższe,]
16
ankieta_01b
PREFEROWANY TYP SKLEPU
7
[SUPERMARKET, SUPER, OSIEDLOWY, BAZAR, BAZAREK...
17
ankieta_01b
preferowana marka sklepu
11
[LIDL, LEWIATAN, ŻABKA, POLOMARKET, ALDI, BIED...
18
ankieta_01b
preferowanay towar
7
[Mięso i wędliny, Produkty zbożowe, Produkty m...
19
ankieta_01b
preferowany rodzaj promocji
6
[gazetka, karta, reklama, nie, sugestia, nan]
20
ankieta_01b
preferowany rodzaj promocji.1
4
[nan, RTV, korzystam, kasjera]
21
ankieta_01b
czynnik zakupowy
9
[cena, jakość, marka, dostępność, lokalność, o...
22
ankieta_02
id.
125
[R_001, R_002, R_003, R_004, R_005, R_006, R_0...
23
ankieta_02
miara
2
[dochody roczne, wydatki_na_żywność_mc]
24
ankieta_02
wartość
129
[54, 750, 26, 2300, 50, 430, 45, 507, 28, 0, -...
25
miasta
kod_miasta
90
[M_001, M_002, M_003, M_004, M_005, M_006, M_0...
26
miasta
Miasto
89
[Warszawa, Kraków, Łódź, Wrocław, Poznań, Gdań...
27
miasta
Liczba ludności
90
[1790658, 779115, 684113, 641607, 538633, 4709...
Nazwa
Liczba kolumn
Liczba wierszy
0
ankieta_01a
11
62
1
ankieta_01b
11
66
2
ankieta_02
3
250
3
miasta
3
90
WYŚWIETLENIE ZAWARTOŚCI TABEL - 5 pierwszych wierszy
Tabela: ankieta_01a
id.
kod_miasta
wiek|liczba osób w rodzinie
m_wykształcenie
k_wykształcenie
PREFEROWANY TYP SKLEPU
preferowana marka sklepu
preferowanay towar
preferowany rodzaj promocji
preferowany rodzaj promocji.1
czynnik zakupowy
0
R_001
M_058
30|2
podstawowe
NaN
BAZAREK
POLOMARKET
Napoje
sugestia
kasjera
cena
1
R_002
M_050
16|1
podstawowe
NaN
BAZAREK
NETTO
Owoce i warzywa
gazetka
NaN
dostępność
2
R_003
M_069
49|1
podstawowe.
NaN
BAZAREK
BIEDRONKA
Produkty piekarnicze
reklama
RTV
jakość
3
R_004
M_059
67 lat|1
podstawowe
NaN
OSIEDLOWY
LIDL
Produkty piekarnicze
gazetka
NaN
jakość
4
R_005
M_057
38|5
zawodowe
NaN
OSIEDLOWY
LIDL
Mięso i wędliny
gazetka
NaN
jakość
Tabela: ankieta_01b
id.
kod_miasta
wiek|liczba osób w rodzinie
m_wykształcenie
k_wykształcenie
PREFEROWANY TYP SKLEPU
preferowana marka sklepu
preferowanay towar
preferowany rodzaj promocji
preferowany rodzaj promocji.1
czynnik zakupowy
0
R_060
M_048
58|2
NaN
średnie
SUPERMARKET
LIDL
Mięso i wędliny
gazetka
NaN
cena
1
R_061
M_014
46|4
NaN
ś
SUPERMARKET
LEWIATAN
Produkty zbożowe
gazetka
NaN
jakość
2
R_062
M_062
16|4
NaN
średnie
SUPERMARKET
ŻABKA
Produkty zbożowe
karta
NaN
jakość
3
R_063
M_053
28|2
NaN
średnie
SUPER
ŻABKA
Produkty mleczne
reklama
RTV
jakość
4
R_064
M_041
55|5
NaN
średnie
SUPERMARKET
POLOMARKET
Produkty mleczne
gazetka
NaN
cena
Tabela: ankieta_02
id.
miara
wartość
0
R_001
dochody roczne
54
1
R_001
wydatki_na_żywność_mc
750
2
R_002
dochody roczne
26
3
R_002
wydatki_na_żywność_mc
2300
4
R_003
dochody roczne
50
Tabela: miasta
kod_miasta
Miasto
Liczba ludności
0
M_001
Warszawa
1790658
1
M_002
Kraków
779115
2
M_003
Łódź
684113
3
M_004
Wrocław
641607
4
M_005
Poznań
538633
2. Uporządkowanie danych
2.1.Określenie zasad uporządkowanego zbioru danych
Czym są dane uprządkowane?
Koncepcja danych uporządkowanych (tidy data) została opisana przez Hadleya Wickhama i stanowi zbiór zasad, które mają na celu ujednolicenie struktury danych, aby ułatwić ich analizę, manipulację i wizualizację.
Kluczowym założeniem tidy data jest to, że dane powinny być przedstawione w sposób „czysty”, co eliminuje niejednoznaczności i pozwala stosować zunifikowane podejście do operacji na danych.
Zasady tidy data służą do tworzenia struktury danych, która maksymalizuje efektywność procesów analitycznych, pozwala na automatyzację rutynowych zadań oraz minimalizuje ryzyko popełnienia błędów przy dalszej obróbce i modelowaniu danych.
Zasady danych uporządkowanych
📌 Podstawowe zasady:
Każda zmienna tworzy kolumnę.
Każda obserwacja tworzy wiersz.
Każdy rodzaj jednostki tworzy tabelę.
🎯 Korzyści uporządkowania danych:
Ułatwia przekształcanie, analizę i wizualizację.
Zapewnia ustrukturyzowany i ustandaryzowany sposób organizacji danych.
Łączy fizyczny układ danych z ich semantyką.
🛠 Struktura ramki danych:
Kolumny reprezentują nazwy zmiennych (etykiety).
Wiersze zawierają wartości obserwacji.
🔍 Semantyka danych:
Zbiór danych to zbiór wartości:
Liczby → dla zmiennych ilościowych.
Ciągi znaków → dla zmiennych jakościowych.
Każda wartość należy do konkretnej:
Zmiennej (kolumna).
Obserwacji (wiersz).
2.2. Identyfikacja czy posiadane dane posiadają oznaki danych nieuporządkowych
W zebranych danych zidentyfikowano oznaki danych nieuporządkowanych:
Podzielone obserwacje tych samych zmiennych pomiędzy wiele tabel
ankieta_01a
ankieta_01b
Przechowywanie w rożnych wierszach jednej kolumny wartosci wielu zmiennych
ankieta_02
Używanie jaka nagłówków kolumn wartosci zamiast nazw zmiennych
ankieta_01a
ankieta_01b
Podzielone wartości jednej zmiennej pomiędzy kilka kolumn
ankieta_01a
ankieta_01b
Przechowywanie w jednej kolumnie połączonych wartosci wielu zmiennych.
Zebrane dane podzielonone pomiędzy wiele plików
ankieta_01a
ankieta_01b
ankieta_02
miasta
Zebrane dane w plikach zostały zapisane w różnych formatach
*.xlsx
*.csv
*.json
Powyższe niezgodności i nieprawidłowości w danych należy przekształcić, połączyć. W rezultacie powinnismy otrzymać jeden plik danych zawiejający dane,które będą w następnym etapie stnowić bazę do procesu czyszczenia danych
2.3. Proces porządkowania danych
Code
display(Markdown(f"#### Niezgodnośc nr 1. Dane z ankiety [ankieta_01] zostały pozielona na dwa pliki: ankieta_01a i ankieta_01b"))display(Markdown(f"* Rozwiązaniem jest połączenie tych plików w jeden pod nazwą (ankieta_01)"))display(Markdown(f"* Przed połączeniem należy sprawdzić zgodnośc tabel w zakresie kolumn"))iflist(ankieta_01a.columns) ==list(ankieta_01b.columns): display(Markdown(f"* Dane zgodne")) display(Markdown(f"Liczba wierszy w ankieta_01a: {len(ankieta_01a)}")) display(Markdown(f"Liczba wierszy w ankieta_01b: {len(ankieta_01b)}"))else: display(Markdown(f"*Dane niezgodne"))ankieta_01 = pd.concat([ankieta_01a, ankieta_01b], axis=0)display(Markdown(f"dane z dwóch plków połączno w jeden ankieta_01: "))display(Markdown(f"Suma wierszy w ankieta_01: {ankieta_01.shape[0]}"))#display(ankieta_01)#---------------------------------------------------------------------------------------------------print()display(Markdown(f"#### Niezgodność nr 2. W jednej kolumnie [miara] przechowywane są nazwy 2 różnych zmiennych a w kolumnie [wartość] wartosci odpowiadające różnym zmiennych w pliku ankieta_02"))display(ankieta_02.head())display(Markdown(f"* Rozwiązaniem jest dokonanie przekształcenia kolumnowo-wierszowego tzw. unpivot - unstack"))ankieta_02 = ankieta_02.set_index(['id.', 'miara']).unstack().reset_index()display(Markdown(f"* Przekształcona tabela ankieta_02"))display(ankieta_02.head(4))print()display(Markdown(f"#### Niezgodnośc nr 3. Używanie jaka nagłówków kolumn wartosci zamiast nazw zmiennych - Zmienna wykształcenie i płeć zostały połączone w jednej kolumnie"))display(Markdown(f"* Rozwiązaniem jest dokonanie przekształcenia kolumnowo-wierszowego tzw. pivot - stack"))display(Markdown(f"* oraz zamiany nazw kolumn"))display(ankieta_01[['id.', 'm_wykształcenie', 'k_wykształcenie']].sample(5))t1=ankieta_01[['id.','m_wykształcenie','k_wykształcenie']]t1=t1.set_index('id.').stack().reset_index()t1.columns = ['id.', 'typ_wykształcenia', 'wykształcenie']t1['typ_wykształcenia'] = t1['typ_wykształcenia'].str.replace('_wykształcenie', '')t1 = t1.rename(columns={'typ_wykształcenia': 'płeć'})ankieta_01 = pd.merge(ankieta_01, t1, on ='id.',how ='left' )ankieta_01 = ankieta_01.drop(['m_wykształcenie','k_wykształcenie'], axis=1)display(Markdown(f"* Przekształcone kolumny m_wykształcenie','k_wykształcenie' tabela ankieta_02"))display(ankieta_01[['id.','płeć', 'wykształcenie']].sample(5))print()#---------------------------------------------------------------------------------------------------#Podzielone wartości jednej zmiennej pomiędzy kilka kolumn#Zmienna preferowany rodzaj promocji została podzielona na dwie kolumnydisplay(Markdown(f"#### Niezgodnośc nr 4. Podzielone wartości jednej zmiennej pomiędzy kilka kolumn: 'preferowany rodzaj promocji','preferowany rodzaj promocji.1"))display(Markdown(f"* Rozwiązaniem jest dokonanie połączenia (cat) preferowany rodzaj promocji w jedną kolumnę"))display(ankieta_01[['id.','preferowany rodzaj promocji','preferowany rodzaj promocji.1']].head(3))ankieta_01['preferowany rodzaj promocji.1']=ankieta_01['preferowany rodzaj promocji.1'].fillna('_')ankieta_01['rodzaj promocji'] = ankieta_01['preferowany rodzaj promocji'].astype(str).str.cat(ankieta_01['preferowany rodzaj promocji.1'].astype(str), sep=' ')ankieta_01['rodzaj promocji'] = ankieta_01['rodzaj promocji'].str.replace('_','') # usunieto zbędne znaki_ankieta_01= ankieta_01.drop('preferowany rodzaj promocji', axis=1) # usunięcie zbędnej kolumnyankieta_01= ankieta_01.drop('preferowany rodzaj promocji.1', axis=1) # usunięcie zbędnej kolumnydisplay(ankieta_01[['id.','rodzaj promocji']].head(3))print()#---------------------------------------------------------------------------------------------------#### 2.2.6. Niezgodność nr 6. Przechowywanie w jednej kolumnie połączonych wartosci wielu zmiennych.display(Markdown(f"#### Niezgodnośc nr 5. Przechowywanie w jednej kolumnie połączonych wartosci wielu zmiennych ('wiek|liczba osób w rodzinie') "))display(Markdown(f"* Rozwiązaniem jest dokonanie podzielenia kolumny (split) ('wiek|liczba osób w rodzinie') na dwie kolumny :(,'wiek', 'liczba osób w rodzinie') "))display(ankieta_01[['id.','wiek|liczba osób w rodzinie']].head(3))ankieta_01[['wiek', 'liczba osób w rodzinie']] = ankieta_01['wiek|liczba osób w rodzinie'].str.split('|', expand=True) # podzielenie kolumnyankieta_01= ankieta_01.drop('wiek|liczba osób w rodzinie', axis=1) # usunięcie zbędnej kolumnydisplay(ankieta_01[['id.','wiek', 'liczba osób w rodzinie']].head(3))print()#---------------------------------------------------------------------------------------------------#### 2.2.7. Niezgodność nr 7. Zmienne podzielonone pomiędzy wiele tabeldisplay(Markdown(f"#### Niezgodnośc nr 6. Zmienne podzielonone pomiędzy wiele tabel w wielu plikach: (ankieta_01, ankieta_02, miasta )"))display(Markdown(f"* Rozwiązaniem jest dokonanie połączenia (merge) 3 tabel w jedną tabelę (baza)) "))ankieta_01 = pd.merge(ankieta_01, miasta, on ='kod_miasta',how ='left')#ankieta_01= ankieta_01.drop('kod_miasta', axis=1) ankieta_02.columns= ankieta_02.columns.to_flat_index()ankieta_02.columns = ['id.', 'dochody', 'wydatki']baza= pd.merge(ankieta_01,ankieta_02, on ='id.')display(baza.head())
Niezgodnośc nr 1. Dane z ankiety [ankieta_01] zostały pozielona na dwa pliki: ankieta_01a i ankieta_01b
Rozwiązaniem jest połączenie tych plików w jeden pod nazwą (ankieta_01)
Przed połączeniem należy sprawdzić zgodnośc tabel w zakresie kolumn
Dane zgodne
Liczba wierszy w ankieta_01a: 62
Liczba wierszy w ankieta_01b: 66
dane z dwóch plków połączno w jeden ankieta_01:
Suma wierszy w ankieta_01: 128
Niezgodność nr 2. W jednej kolumnie [miara] przechowywane są nazwy 2 różnych zmiennych a w kolumnie [wartość] wartosci odpowiadające różnym zmiennych w pliku ankieta_02
id.
miara
wartość
0
R_001
dochody roczne
54
1
R_001
wydatki_na_żywność_mc
750
2
R_002
dochody roczne
26
3
R_002
wydatki_na_żywność_mc
2300
4
R_003
dochody roczne
50
Rozwiązaniem jest dokonanie przekształcenia kolumnowo-wierszowego tzw. unpivot - unstack
Przekształcona tabela ankieta_02
id.
wartość
miara
dochody roczne
wydatki_na_żywność_mc
0
R_001
54
750
1
R_002
26
2300
2
R_003
50
430
3
R_004
45
507
Niezgodnośc nr 3. Używanie jaka nagłówków kolumn wartosci zamiast nazw zmiennych - Zmienna wykształcenie i płeć zostały połączone w jednej kolumnie
Rozwiązaniem jest dokonanie przekształcenia kolumnowo-wierszowego tzw. pivot - stack
Niezgodnośc nr 4. Podzielone wartości jednej zmiennej pomiędzy kilka kolumn: ‘preferowany rodzaj promocji’,’preferowany rodzaj promocji.1
Rozwiązaniem jest dokonanie połączenia (cat) preferowany rodzaj promocji w jedną kolumnę
id.
preferowany rodzaj promocji
preferowany rodzaj promocji.1
0
R_001
sugestia
kasjera
1
R_002
gazetka
NaN
2
R_003
reklama
RTV
id.
rodzaj promocji
0
R_001
sugestia kasjera
1
R_002
gazetka
2
R_003
reklama RTV
Niezgodnośc nr 5. Przechowywanie w jednej kolumnie połączonych wartosci wielu zmiennych (‘wiek|liczba osób w rodzinie’)
Rozwiązaniem jest dokonanie podzielenia kolumny (split) (‘wiek|liczba osób w rodzinie’) na dwie kolumny :(,‘wiek’, ‘liczba osób w rodzinie’)
id.
wiek|liczba osób w rodzinie
0
R_001
30|2
1
R_002
16|1
2
R_003
49|1
id.
wiek
liczba osób w rodzinie
0
R_001
30
2
1
R_002
16
1
2
R_003
49
1
Niezgodnośc nr 6. Zmienne podzielonone pomiędzy wiele tabel w wielu plikach: (ankieta_01, ankieta_02, miasta )
Rozwiązaniem jest dokonanie połączenia (merge) 3 tabel w jedną tabelę (baza))
id.
kod_miasta
PREFEROWANY TYP SKLEPU
preferowana marka sklepu
preferowanay towar
czynnik zakupowy
płeć
wykształcenie
rodzaj promocji
wiek
liczba osób w rodzinie
Miasto
Liczba ludności
dochody
wydatki
0
R_001
M_058
BAZAREK
POLOMARKET
Napoje
cena
m
podstawowe
sugestia kasjera
30
2
Głogów
68170
54
750
1
R_002
M_050
BAZAREK
NETTO
Owoce i warzywa
dostępność
m
podstawowe
gazetka
16
1
Suwałki
69442
26
2300
2
R_003
M_069
BAZAREK
BIEDRONKA
Produkty piekarnicze
jakość
m
podstawowe.
reklama RTV
49
1
Świdnica
60281
50
430
3
R_004
M_059
OSIEDLOWY
LIDL
Produkty piekarnicze
jakość
m
podstawowe
gazetka
67 lat
1
Stargard
71464
45
507
4
R_005
M_057
OSIEDLOWY
LIDL
Mięso i wędliny
jakość
m
zawodowe
gazetka
38
5
Ostrowiec Świętokrzyski
69715
28
750
3.Czyszczenie danych
3.1 Wprowadzenie
Czym jest Czyszczenie danych? - kliknij, aby rozwinąć
Odpowiedzią na ww. nieprawidłowości będą odpowiednie oczyszczenie danych z błędów. 1. Zdefiniowanie czystych danych: - Dane muszą być dokładne. - Kompletne. - Spójne. - Ważne. - Aktualne. - Bez duplikatów. - Jednolite.
Rozpoznanie „brudnych” danych:
Możliwe oznaki zanieczyszczonych danych:
Różna pisownia wariantów zmiennej tekstowej
Zbędne myślniki.
Litery drukowane.
Wartości niezgodne z rzeczywistością.
Zbędne odstępy.
Literówki.
Dane niezgodne z wiedzą dziedzinową.
Dane niezgodne ze zdrowym rozsądkiem.
Wartości liczbowe we wartościach zmiennej kategorycznej, gdzie powinna być wartość tekstowa.
Wartości tekstowe w zmiennych ilościowych.
Duplikaty.
Myślniki zamiast wartości.
Zera zamiast wartości.
Wartości brakujące-puste.
Różne jednostki jednej zmiennej.
Zalety czyszczenia danych:
Poprawa jakości danych: Usunięcie błędów, brakujących wartości i anomalii, co zapobiega błędnym wnioskom.
Zwiększenie wydajności modeli ML: Dobrze przygotowane dane poprawiają skuteczność algorytmów uczenia maszynowego.
Redukcja szumu: Minimalizuje wpływ nieistotnych lub błędnych informacji.
Lepsza interpretacja wyników: Przejrzyste i dobrze przygotowane dane ułatwiają analizę i wyciąganie wniosków.
Efektywność obliczeniowa: Optymalizacja struktury danych zmniejsza czas i zasoby potrzebne do analizy.
Odpowiedzią na ww. nieprawidłowości będzie odpowiednie oczyszczenie danych z błędów.
3.2. Identyfikacja błędnych danych
W zebranych danych zidentyfikowano błędne i nieprawidłowe dane:
Niejednolite nazwy kolumn
Niejednoznaczna kolejnośc kolumn
Błędy w kolumnach tekstowych
różna wielkosć liter wartości tekstowych w wybranych kolumnach
wartości zawierają znaki nie literowe
wartości z poza zakresu wartosci dozwolonych (wartosci referencyjnych)
Błędy w kolumnach liczbowych
wartości zawierają znaki nie liczbowe
różne typy zmiennych, typy nie zgodne z założeniami
wartości z poza zakresu wartosci dozwolonych (wartosci referencyjnych)
Określenie
Code
display(Markdown(f"#### Niezgodnośc nr 1. Różna wielkość liter w nazwach kolumn"))display(Markdown(f"#### Niezgodnośc nr 2. Nazwy zawiarają znaki nie będące literami (_)"))display(Markdown(f"#### Niezgodnośc nr 3. Nieadekwatna kolejność kolumn"))display(Markdown(f"* Rozwiązaniem jest - Ujednolicenie wielkości liter oraz usunięcie znaków nie będących literami i zmiana kolejności kolumn"))display(Markdown(f"* Nazwy kolumn przed zmianami:"))display(baza.columns.to_list())baza.columns = baza.columns.str.lower().str.replace("_"," ")kolejnosc = ['id.', 'płeć', 'wykształcenie', 'wiek','liczba osób w rodzinie','preferowany typ sklepu', 'preferowana marka sklepu','preferowanay towar', 'czynnik zakupowy','rodzaj promocji', 'miasto','liczba ludności','dochody', 'wydatki']baza= baza[kolejnosc]display(Markdown(f"* Nazwy kolumn po zmianach:"))display(baza.columns.to_list())print()display(Markdown(f"#### Niezgodnośc nr 4. Rózna wielkość liter wartości tekstowych w wybranych kolumnach"))display(Markdown(f"* Rozwiązaniem jest - Ujednolicenie wielkości"))display(baza.head(3))zmienna_tekstowa= ['płeć', 'wykształcenie','preferowany typ sklepu','preferowana marka sklepu', 'preferowanay towar', 'czynnik zakupowy','rodzaj promocji']#Zamiana drukowanych liter na małebaza[zmienna_tekstowa]=baza[zmienna_tekstowa].applymap(lambda x: x.lower() ifisinstance(x, str) else x)display(Markdown(f"* tabela po zmianach:"))display(baza.head(3))print()display(Markdown(f"#### Niezgodnośc nr 5. Wartości w kolumnach tekstowych zawieraja niezdozwolone znaki nie literowe "))display(Markdown(f"* Rozwiązaniem jest - Usunięcie zbędnych znaków ('[A-Z]|[0-9]|_|,|W|\.|\?|-'"))zmienna_liczbowa = [ 'wiek','liczba osób w rodzinie','liczba ludności','dochody', 'wydatki', 'od', 'do', 'średnia częstość zakupów w tyg']znaki = (r'[A-Z]|[0-9]|_|,|W|\.|\?|-')zmienna_tekstowa= ['płeć', 'wykształcenie','preferowany typ sklepu','preferowana marka sklepu', 'preferowanay towar', 'czynnik zakupowy','rodzaj promocji']display(Markdown(f"* Dane, które zawierają niedozwolone znaki: *"))for zmienna in zmienna_tekstowa: czy_inne_znaki = baza[zmienna].str.contains(znaki, na=False)ifany(czy_inne_znaki) ==True: display(baza.loc[czy_inne_znaki, ['id.',zmienna]])for zmienna in zmienna_tekstowa: czy_inne_znaki = baza[zmienna].str.contains(znaki, na=False)ifany(czy_inne_znaki) ==True: baza[zmienna] = baza[zmienna].str.replace(znaki,"")display(Markdown(f"* Dane po poprawkach: *"))for zmienna in zmienna_tekstowa: czy_inne_znaki = baza[zmienna].str.contains(znaki, na=False)ifany(czy_inne_znaki) ==True: display(baza.loc[czy_inne_znaki, ['id.',zmienna]])display(Markdown(f"#### Niezgodnośc nr 6. kolumny zmiennych tekstowych zawierają niedozwolone wartoci z poza zakresu referencyjnego "))display(Markdown(f"* Rozwiązaniem jest - zdefiniowanie zakresu wartosci referencyjnych dla zmiennych, "))display(Markdown(f"* Sprawdzenie, w których kolumnach występują niezgodności "))display(Markdown(f"* Dokonanie zmian błednych danych, "))reference_values = {"Zmienna": ["płeć", "wykształcenie", "preferowany typ sklepu", "preferowana marka sklepu", "preferowany towar", "czynnik zakupowy", "rodzaj promocji", "miasto"],"Zakres wartości": ["mężczyzna, kobieta", "podstawowe, zawodowe, średnie, wyższe", "bazarek, osiedlowy, supermarket, galeria", "dowolne", "dowolne", "dowolne", "sugestia kasjera, gazetka, reklama RTV, sms, e-mail, karta, aplikacja, nie korzystam", "dowolne"] }reference_df = pd.DataFrame(reference_values)display(Markdown(f"* Wartości referencyjne dla zmiennych tekstowych:"))display(reference_df)płeć_ref = ['m', 'k']preferowany_typ_sklepu_ref = ['bazarek', 'osiedlowy', 'supermarket', 'galeria']wykształcenie_ref = ['podstawowe', 'zawodowe', 'średnie', 'wyższe']niepasujące_dane_kolumna1 = baza.loc[~baza['płeć'].isin(płeć_ref)]niepasujące_dane_kolumna2 = baza.loc[~baza['preferowany typ sklepu'].isin(preferowany_typ_sklepu_ref)]niepasujące_dane_kolumna3 = baza.loc[~baza['wykształcenie'].isin(wykształcenie_ref)]ifnot niepasujące_dane_kolumna1.empty:print("Niepasujące dane w kolumnie 'płeć':") display(niepasujące_dane_kolumna1[['płeć']])ifnot niepasujące_dane_kolumna2.empty:print("Niepasujące dane w kolumnie 'preferowany typ sklepu':") display(niepasujące_dane_kolumna2[['preferowany typ sklepu']])ifnot niepasujące_dane_kolumna3.empty:print("Niepasujące dane w kolumnie 'wykształcenie':") display(niepasujące_dane_kolumna3[['wykształcenie']])print()dict_wyk={'średn':'średnie', 'ś': 'średnie', 'w':'wyższe'}baza['wykształcenie'] = baza['wykształcenie'].replace(dict_wyk)preferowany_typ_sklepu_ref = {'super': 'supermarket', 'bazar':'bazarek'}baza['preferowany typ sklepu'] = baza['preferowany typ sklepu'].replace(preferowany_typ_sklepu_ref)baza['preferowana marka sklepu'] = baza['preferowana marka sklepu'].str.title()custom_order = ['podstawowe', 'zawodowe','średnie', 'wyższe']cat_dtype = pd.CategoricalDtype(categories=custom_order, ordered=True)# Zmiana typu kolumny na "categorical" z zdefiniowanym porządkiembaza['wykształcenie'] = baza['wykształcenie'].astype(cat_dtype)zmienna_tekstowa= ['płeć','preferowany typ sklepu','preferowana marka sklepu', 'preferowanay towar', 'czynnik zakupowy','rodzaj promocji']baza[zmienna_tekstowa]=baza[zmienna_tekstowa].astype('category')display(Markdown(f"* wartości unikatowe zmiennych po zmianie:"))unique_wykształcenie = baza['wykształcenie'].unique().tolist()unique_typ_sklepu = baza['preferowany typ sklepu'].unique().tolist()print("Unikatowe wartości wykształcenia:", unique_wykształcenie)print("Unikatowe wartości typu sklepu:", unique_typ_sklepu)print()#--------------------------------------------------------------------------------------------------------------------------------------display(Markdown(f"#### Niezgodnośc nr 7. kolumny zmiennych liczbowych zawierają niedozwolone wartości z poza zakresu referencyjnego "))display(Markdown(f"#### Niezgodnośc nr 8. kolumny zmiennych liczbowych zawierają niedozwolone znaki, np. zł, PLN "))display(Markdown(f"* Rozwiązaniem jest - zdefiniowanie zakresu wartosci referencyjnych dla zmiennych, "))display(Markdown(f"* Sprawdzenie, w których kolumnach występują niezgodności "))display(Markdown(f"* Dokonanie zmian błednych danych lub zamianę na NaN "))display(Markdown(f"* Wartości referencyjne dla zmiennych liczbowych:"))dane = {"Cecha": ["wiek","liczba osób w rodzinie","dochody","wydatki","dodatkowy parametr" ],"Dozwolone wartości": ["18 - 105","1 - 10","> 0","> 0","dochody > wydatki" ]}df = pd.DataFrame(dane)display(df)display(Markdown(f"* Sprawdzenie czy w zmiennych liczbowych znajduję się znaki nienumeryczne:"))zmienna_liczbowa = ['wiek', 'liczba osób w rodzinie', 'dochody', 'wydatki']for kolumna in zmienna_liczbowa: czy_inne_znaki = baza[kolumna].astype(str).str.contains('\D')print(f'"{kolumna}" zawiera znaki nie liczbowe : --> {any(czy_inne_znaki)}')ifany(czy_inne_znaki): display(baza.loc[czy_inne_znaki, ['id.', kolumna]])print()#pOPRAWA # # Numer indeksów, dla których chcemy zmienić wartości na NaN# indexes_to_replace = [10,5,34,35,77,103,1]# for index in indexes_to_replace:# baza.at[index, 'dochód'] = np.nandef konwertuj_na_int(wartosc):returnint(wartosc.replace(' zł', '').replace(' PLN', '').replace(' ', ''))# Konwersja wartości w kolumnie 'dochody' na intbaza['dochody'] = baza['dochody'].apply(konwertuj_na_int)# Konwersja wartości w kolumnie 'wydatki' na intbaza['wydatki'] = baza['wydatki'].apply(konwertuj_na_int)baza['dochody']=baza['dochody']*1000baza['wydatki']=baza['wydatki']*12# Konwersja zmiennych z 'object' na 'int64'baza['wiek'] = pd.to_numeric(baza['wiek'], errors='coerce').astype('float')baza['liczba osób w rodzinie'] = pd.to_numeric(baza['liczba osób w rodzinie'], errors='coerce').astype('float')display(Markdown(f"* Sprawdzenie czy w zmiennych liczbowych znajduję się wartości z poza zakresu referencyjnego:"))#---------------------------------from IPython.display import display, Markdowndef sprawdz_niezgodnosc(df, warunek, komunikat_bledu, kolumny, nazwa_zmiennej):ifany(warunek): display(Markdown(f'**{komunikat_bledu}**')) display(df.loc[warunek, kolumny])else: display(Markdown(f'**Brak niezgodności w zmiennej "{nazwa_zmiennej}".**'))# --- Sprawdzanie niezgodności w zmiennej 'dochody' ---# Warunek: wartości mniejsze od 0 lub równe 0warunek_dochody = (baza['dochody'] <0) | (baza['dochody'] ==0)sprawdz_niezgodnosc( df=baza, warunek=warunek_dochody, komunikat_bledu='Zmienna "dochody" zawiera wartości < 0 lub = 0.', kolumny=['id.', 'dochody'], nazwa_zmiennej='dochody')# --- Sprawdzanie niezgodności w zmiennej 'wydatki' ---# Warunek: wartości mniejsze od 0warunek_wydatki = (baza['wydatki'] <0)sprawdz_niezgodnosc( df=baza, warunek=warunek_wydatki, komunikat_bledu='Zmienna "wydatki" zawiera wartości < 0.', kolumny=['id.', 'wydatki'], nazwa_zmiennej='wydatki')# --- Sprawdzanie niezgodności między 'wydatki' a 'dochody' ---# Warunek: wydatki są większe od dochodówwarunek_wydatki_dochody = baza['wydatki'] > baza['dochody']sprawdz_niezgodnosc( df=baza, warunek=warunek_wydatki_dochody, komunikat_bledu='Istnieją wydatki większe od dochodów.', kolumny=['id.', 'dochody', 'wydatki'], nazwa_zmiennej='wydatki i dochody')# --- Sprawdzanie niezgodności w zmiennej 'wiek' ---# Warunek: wiek poza zakresem 15-105 latwarunek_wiek = (baza['wiek'] <15) | (baza['wiek'] >105)sprawdz_niezgodnosc( df=baza, warunek=warunek_wiek, komunikat_bledu='Zmienna "wiek" zawiera wartości spoza zakresu 15-105.', kolumny=['id.', 'wiek'], nazwa_zmiennej='wiek')# --- Sprawdzanie niezgodności w zmiennej 'liczba osób w rodzinie' ---# Warunek: liczba osób w rodzinie spoza zakresu 1-10warunek_liczba_osob = (baza['liczba osób w rodzinie'] <1) | (baza['liczba osób w rodzinie'] >10)sprawdz_niezgodnosc( df=baza, warunek=warunek_liczba_osob, komunikat_bledu='Zmienna "liczba osób w rodzinie" zawiera wartości spoza zakresu 1-10.', kolumny=['id.', 'liczba osób w rodzinie'], nazwa_zmiennej='liczba osób w rodzinie')display(Markdown(f"Z tych danych wynika, że są to błędne wpisy."))display(Markdown(f"Z uwagi na niewielką ilość pozyskanych danych usuwanie takich danych znacznie zmniejszyło by liczbę dostępych danych, dlatego zostanie dokonana zamiana błędych wartosci na wartości brakujące, następnie w dalszych krokach braki zostaną obsłużone."))print()display(Markdown(f"* tabela zmiennych i nr wierszy do dokonania zmian błędnych danych na wartości brakujące NaN"))cond_dochody = (baza['dochody'] <0) | (baza['dochody'] ==0)# b) Zmienna 'wydatki' - wartości mniejsze niż 0cond_wydatki = (baza['wydatki'] <0)# c) Niezgodność między 'wydatki' a 'dochody' - wydatki większe od dochodówcond_wydatki_dochody = (baza['wydatki'] > baza['dochody'])# d) Zmienna 'wiek' - wartości spoza zakresu 15-105cond_wiek = (baza['wiek'] <15) | (baza['wiek'] >105)# e) Zmienna 'liczba osób w rodzinie' - wartości spoza zakresu 1-10cond_liczba_osob = (baza['liczba osób w rodzinie'] <1) | (baza['liczba osób w rodzinie'] >10)# 2. Pobranie numerów indeksów (wierszy), które spełniają powyższe warunki:indeksy_dochody =list(baza.index[cond_dochody])indeksy_wydatki =list(baza.index[cond_wydatki])indeksy_wydatki_dochody =list(baza.index[cond_wydatki_dochody])indeksy_wiek =list(baza.index[cond_wiek])indeksy_liczba_osob =list(baza.index[cond_liczba_osob])# 3. Tworzenie nowego DataFrame z informacjami o niezgodnościach:df_nieprawidlowe = pd.DataFrame({'zmienna': ['dochody', 'wydatki', 'wydatki > dochody', 'wiek', 'liczba osób w rodzinie'],'nr wiersza do zmiany': [indeksy_dochody, indeksy_wydatki, indeksy_wydatki_dochody, indeksy_wiek, indeksy_liczba_osob]})# Wyświetlenie utworzonego DataFramedisplay(df_nieprawidlowe)# 2. Zamiana wartości na NaN w odpowiednich kolumnach:# Dla 'dochody'baza.loc[cond_dochody, 'dochody'] = np.nan# Dla 'wydatki'baza.loc[cond_wydatki, 'wydatki'] = np.nan# Dla niezgodności: wydatki większe od dochodów – zamieniamy obie wartości na NaNbaza.loc[cond_wydatki_dochody, ['dochody', 'wydatki']] = np.nan# Dla 'wiek'baza.loc[cond_wiek, 'wiek'] = np.nan# Dla 'liczba osób w rodzinie'baza.loc[cond_liczba_osob, 'liczba osób w rodzinie'] = np.nandisplay(Markdown(f"* Ponowne sprawdzenie poprawnosci referencyjnej zmiennych liczbowych:"))# Sprawdzanie niezgodności w zmiennej 'dochody'czy_ujemne = (baza['dochody'] <0)czy_zero = (baza['dochody'] ==0)ifany(czy_ujemne) orany(czy_zero):print(f'Zmienna "dochody" zawiera wartości < 0 lub = 0.') display(baza.loc[czy_ujemne | czy_zero, ['id.', 'dochody']])else:print('Brak niezgodności w zmiennej "dochody".')# Sprawdzanie niezgodności w zmiennej 'wydatki'czy_ujemne = (baza['wydatki'] <0)ifany(czy_ujemne):print(f'Zmienna "wydatki" zawiera wartości < 0.') display(baza.loc[czy_ujemne, ['id.', 'wydatki']])else:print('Brak niezgodności w zmiennej "wydatki".')# Sprawdzanie niezgodności między 'wydatki' a 'dochody'czy_wieksze_wydatki = baza['wydatki'] > baza['dochody']ifany(czy_wieksze_wydatki):print('Istnieją wydatki większe od dochodów.') display(baza.loc[czy_wieksze_wydatki, ['id.', 'dochody', 'wydatki']])else:print('Brak niezgodności między wydatkami a dochodami.')# Sprawdzanie niezgodności w zmiennej 'wiek'czy_poza_zakresem = (baza['wiek'] <15) | (baza['wiek'] >105)ifany(czy_poza_zakresem):print('Zmienna "wiek" zawiera wartości spoza zakresu 15-105.') display(baza.loc[czy_poza_zakresem, ['id.', 'wiek']])else:print('Brak niezgodności w zmiennej "wiek".')# Sprawdzanie niezgodności w zmiennej 'liczba osób w rodzinie'czy_poza_zakresem = (baza['liczba osób w rodzinie'] <1) | (baza['liczba osób w rodzinie'] >10)ifany(czy_poza_zakresem):print('Zmienna "liczba osób w rodzinie" zawiera wartości spoza zakresu 1-10.') display(baza.loc[czy_poza_zakresem, ['id.', 'liczba osób w rodzinie']])else:print('Brak niezgodności w zmiennej "liczba osób w rodzinie".')
Niezgodnośc nr 1. Różna wielkość liter w nazwach kolumn
Niezgodnośc nr 2. Nazwy zawiarają znaki nie będące literami (_)
Niezgodnośc nr 3. Nieadekwatna kolejność kolumn
Rozwiązaniem jest - Ujednolicenie wielkości liter oraz usunięcie znaków nie będących literami i zmiana kolejności kolumn
Nazwy kolumn przed zmianami:
['id.',
'kod_miasta',
'PREFEROWANY TYP SKLEPU',
'preferowana marka sklepu',
'preferowanay towar',
'czynnik zakupowy',
'płeć',
'wykształcenie',
'rodzaj promocji',
'wiek',
'liczba osób w rodzinie',
'Miasto',
'Liczba ludności',
'dochody',
'wydatki']
Nazwy kolumn po zmianach:
['id.',
'płeć',
'wykształcenie',
'wiek',
'liczba osób w rodzinie',
'preferowany typ sklepu',
'preferowana marka sklepu',
'preferowanay towar',
'czynnik zakupowy',
'rodzaj promocji',
'miasto',
'liczba ludności',
'dochody',
'wydatki']
Niezgodnośc nr 4. Rózna wielkość liter wartości tekstowych w wybranych kolumnach
Rozwiązaniem jest - Ujednolicenie wielkości
id.
płeć
wykształcenie
wiek
liczba osób w rodzinie
preferowany typ sklepu
preferowana marka sklepu
preferowanay towar
czynnik zakupowy
rodzaj promocji
miasto
liczba ludności
dochody
wydatki
0
R_001
m
podstawowe
30
2
BAZAREK
POLOMARKET
Napoje
cena
sugestia kasjera
Głogów
68170
54
750
1
R_002
m
podstawowe
16
1
BAZAREK
NETTO
Owoce i warzywa
dostępność
gazetka
Suwałki
69442
26
2300
2
R_003
m
podstawowe.
49
1
BAZAREK
BIEDRONKA
Produkty piekarnicze
jakość
reklama RTV
Świdnica
60281
50
430
tabela po zmianach:
id.
płeć
wykształcenie
wiek
liczba osób w rodzinie
preferowany typ sklepu
preferowana marka sklepu
preferowanay towar
czynnik zakupowy
rodzaj promocji
miasto
liczba ludności
dochody
wydatki
0
R_001
m
podstawowe
30
2
bazarek
polomarket
napoje
cena
sugestia kasjera
Głogów
68170
54
750
1
R_002
m
podstawowe
16
1
bazarek
netto
owoce i warzywa
dostępność
gazetka
Suwałki
69442
26
2300
2
R_003
m
podstawowe.
49
1
bazarek
biedronka
produkty piekarnicze
jakość
reklama rtv
Świdnica
60281
50
430
Niezgodnośc nr 5. Wartości w kolumnach tekstowych zawieraja niezdozwolone znaki nie literowe
Rozwiązaniem jest - Usunięcie zbędnych znaków (’[A-Z]|[0-9]|_|,|W|.|?|-’
Dane, które zawierają niedozwolone znaki: *
id.
wykształcenie
2
R_003
podstawowe.
52
R_053
śred5nie
103
R_095
wyższe,
Dane po poprawkach: *
id.
wykształcenie
2
R_003
podstawowe.
52
R_053
śred5nie
103
R_095
wyższe,
Niezgodnośc nr 6. kolumny zmiennych tekstowych zawierają niedozwolone wartoci z poza zakresu referencyjnego
Rozwiązaniem jest - zdefiniowanie zakresu wartosci referencyjnych dla zmiennych,
Sprawdzenie, w których kolumnach występują niezgodności
Dokonanie zmian błednych danych,
Wartości referencyjne dla zmiennych tekstowych:
Zmienna
Zakres wartości
0
płeć
mężczyzna, kobieta
1
wykształcenie
podstawowe, zawodowe, średnie, wyższe
2
preferowany typ sklepu
bazarek, osiedlowy, supermarket, galeria
3
preferowana marka sklepu
dowolne
4
preferowany towar
dowolne
5
czynnik zakupowy
dowolne
6
rodzaj promocji
sugestia kasjera, gazetka, reklama RTV, sms, e...
7
miasto
dowolne
Niepasujące dane w kolumnie 'preferowany typ sklepu':
preferowany typ sklepu
71
super
79
super
84
bazar
85
bazar
120
NaN
126
NaN
Niepasujące dane w kolumnie 'wykształcenie':
wykształcenie
2
podstawowe.
14
średn
52
śred5nie
69
ś
92
w
103
wyższe,
wartości unikatowe zmiennych po zmianie:
Unikatowe wartości wykształcenia: ['podstawowe', nan, 'zawodowe', 'średnie', 'wyższe']
Unikatowe wartości typu sklepu: ['bazarek', 'osiedlowy', 'supermarket', 'galeria', nan]
Niezgodnośc nr 7. kolumny zmiennych liczbowych zawierają niedozwolone wartości z poza zakresu referencyjnego
Niezgodnośc nr 8. kolumny zmiennych liczbowych zawierają niedozwolone znaki, np. zł, PLN
Rozwiązaniem jest - zdefiniowanie zakresu wartosci referencyjnych dla zmiennych,
Sprawdzenie, w których kolumnach występują niezgodności
Dokonanie zmian błednych danych lub zamianę na NaN
Wartości referencyjne dla zmiennych liczbowych:
Cecha
Dozwolone wartości
0
wiek
18 - 105
1
liczba osób w rodzinie
1 - 10
2
dochody
> 0
3
wydatki
> 0
4
dodatkowy parametr
dochody > wydatki
Sprawdzenie czy w zmiennych liczbowych znajduję się znaki nienumeryczne:
"wiek" zawiera znaki nie liczbowe : --> True
id.
wiek
3
R_004
67 lat
11
R_012
33 lata
"liczba osób w rodzinie" zawiera znaki nie liczbowe : --> False
"dochody" zawiera znaki nie liczbowe : --> True
id.
dochody
6
R_007
29 zł
10
R_011
-31
"wydatki" zawiera znaki nie liczbowe : --> True
id.
wydatki
5
R_006
-556
20
R_021
669 PLN
Sprawdzenie czy w zmiennych liczbowych znajduję się wartości z poza zakresu referencyjnego:
Zmienna “dochody” zawiera wartości < 0 lub = 0.
id.
dochody
5
R_006
0
10
R_011
-31000
86
R_078
0
112
R_104
0
Zmienna “wydatki” zawiera wartości < 0.
id.
wydatki
5
R_006
-6672
Istnieją wydatki większe od dochodów.
id.
dochody
wydatki
1
R_002
26000
27600
10
R_011
-31000
7092
86
R_078
0
10692
112
R_104
0
12024
Zmienna “wiek” zawiera wartości spoza zakresu 15-105.
id.
wiek
6
R_007
158.0
Zmienna “liczba osób w rodzinie” zawiera wartości spoza zakresu 1-10.
id.
liczba osób w rodzinie
39
R_040
30.0
Z tych danych wynika, że są to błędne wpisy.
Z uwagi na niewielką ilość pozyskanych danych usuwanie takich danych znacznie zmniejszyło by liczbę dostępych danych, dlatego zostanie dokonana zamiana błędych wartosci na wartości brakujące, następnie w dalszych krokach braki zostaną obsłużone.
tabela zmiennych i nr wierszy do dokonania zmian błędnych danych na wartości brakujące NaN
Brak niezgodności w zmiennej "dochody".
Brak niezgodności w zmiennej "wydatki".
Brak niezgodności między wydatkami a dochodami.
Brak niezgodności w zmiennej "wiek".
Brak niezgodności w zmiennej "liczba osób w rodzinie".
Code
#---------------------------------------------------------------------------------------------------display(Markdown(f"#### Niezgodnośc nr 9. Duplikaty - Sprawdzenie czy w danych występują duplikaty"))display(Markdown(f"* Rozwiązaniem jest dokonanie zidentyfokowanie dublujących się danych , a następnie ich usunięcie "))display(Markdown(f"* Idntyfikacja duplikatów:"))display(Markdown(f"Rozmiar tabeli z duplikatami: {baza.shape}"))duplikaty_df = pd.DataFrame({'Nazwa pliku': ['baza'],'Duplikaty': [baza.duplicated().any()]})display(duplikaty_df)display(Markdown(f"* Wyświetlenie zduplikowanych wierszy:"))display(baza[baza.duplicated()])print(f'UWAGA: Usunięto wiersze ({sum(ankieta_01a.duplicated())}) z duplikującymi się danymi')baza.drop_duplicates(inplace=True)display(Markdown(f"Rozmiar tabeli po usunięciu duplikatów: {baza.shape}"))print()
Niezgodnośc nr 9. Duplikaty - Sprawdzenie czy w danych występują duplikaty
Rozwiązaniem jest dokonanie zidentyfokowanie dublujących się danych , a następnie ich usunięcie
Idntyfikacja duplikatów:
Rozmiar tabeli z duplikatami: (134, 14)
Nazwa pliku
Duplikaty
0
baza
True
Wyświetlenie zduplikowanych wierszy:
id.
płeć
wykształcenie
wiek
liczba osób w rodzinie
preferowany typ sklepu
preferowana marka sklepu
preferowanay towar
czynnik zakupowy
rodzaj promocji
miasto
liczba ludności
dochody
wydatki
57
R_057
k
średnie
69.0
2.0
osiedlowy
Lidl
produkty piekarnicze
cena
gazetka
Ostrów Wielkopolski
67825
41000.0
9948.0
58
R_057
k
średnie
69.0
2.0
osiedlowy
Lidl
produkty piekarnicze
cena
gazetka
Ostrów Wielkopolski
67825
41000.0
9948.0
59
R_057
k
średnie
69.0
2.0
osiedlowy
Lidl
produkty piekarnicze
cena
gazetka
Ostrów Wielkopolski
67825
41000.0
9948.0
61
R_058
k
średnie
47.0
4.0
supermarket
Żabka
produkty mleczne
marka
gazetka
Inowrocław
75535
41000.0
9948.0
62
R_058
k
średnie
47.0
4.0
supermarket
Żabka
produkty mleczne
marka
gazetka
Inowrocław
75535
41000.0
9948.0
63
R_058
k
średnie
47.0
4.0
supermarket
Żabka
produkty mleczne
marka
gazetka
Inowrocław
75535
41000.0
9948.0
65
R_059
k
średnie
26.0
5.0
supermarket
Aldi
mięso i wędliny
cena
sugestia kasjera
Toruń
202386
41000.0
9948.0
66
R_059
k
średnie
26.0
5.0
supermarket
Aldi
mięso i wędliny
cena
sugestia kasjera
Toruń
202386
41000.0
9948.0
67
R_059
k
średnie
26.0
5.0
supermarket
Aldi
mięso i wędliny
cena
sugestia kasjera
Toruń
202386
41000.0
9948.0
UWAGA: Usunięto wiersze (3) z duplikującymi się danymi
Rozmiar tabeli po usunięciu duplikatów: (125, 14)
3.4. Obserwacje nietypowe i odstające
3.4.1. Sprawdzenie czy w zmiennych liczbowych wystepują obserwacje odstające ( naturalne, błędy)
Code
# def outliers(df, var):# data = df[var]# def detect_outliers_iqr(data):# q1, q3 = np.percentile(data, [25, 75])# iqr = q3 - q1# lower_bound = q1 - (1.5 * iqr)# upper_bound = q3 + (1.5 * iqr)# outliers_IQR = [i for i, x in enumerate(data) if x < lower_bound or x > upper_bound]# return outliers_IQR# def detect_outliers_zscore(data):# threshold = 2# z_scores = zscore(data)# outliers_zscore = [i for i, z in enumerate(z_scores) if abs(z) > threshold]# return outliers_zscore# # Reshape the data to a 2D array# data = np.array(data).reshape(-1, 1)# outliers_IQR = detect_outliers_iqr(data)# outliers_zscore = detect_outliers_zscore(data)# df = pd.DataFrame(data)# df['Odstające_IQR'] = np.where(df.index.isin(outliers_IQR), -1, 1)# #df['Odstające_mean_std'] = np.where(df.index.isin(outliers_mean_std), -1, 1)# df['Odstające_Zscore'] = np.where(df.index.isin(outliers_zscore), -1, 1)# # Dodatkowa kolumna: Czy_Odstające# df['Czy_Odstające'] = np.where((df['Odstające_IQR'] == -1) |# (df['Odstające_Zscore'] == -1),# True, False)# df = df.loc[df['Czy_Odstające'] == True]# df = df.rename(columns={0: var}) # Zmiana nazwy kolumny 0 na Nazwa_Zmiennej# # Dodaj kolumnę "ile_ident"# df['ile_ident'] = df[['Odstające_IQR','Odstające_Zscore']].apply(lambda row: row.value_counts().get(-1, 0), axis=1)# return dfimport numpy as npimport pandas as pdfrom scipy.stats import zscoredef detect_outliers_iqr(data: np.ndarray) ->list:""" Wykrywa odchylenia metodą IQR. Parametry: data (np.ndarray): Jednowymiarowa tablica z danymi. Zwraca: list: Lista indeksów, dla których wartość wychodzi poza granice IQR. """ q1, q3 = np.percentile(data, [25, 75]) iqr = q3 - q1 lower_bound = q1 - (1.5* iqr) upper_bound = q3 + (1.5* iqr)return [i for i, x inenumerate(data) if x < lower_bound or x > upper_bound]def detect_outliers_zscore(data: np.ndarray, threshold: float=2) ->list:""" Wykrywa odchylenia metodą Z-score. Parametry: data (np.ndarray): Jednowymiarowa tablica z danymi. threshold (float): Próg wykrywania odchyleń. Zwraca: list: Lista indeksów, dla których wartość z-score przekracza próg. """ z_scores = zscore(data)return [i for i, z inenumerate(z_scores) if np.abs(z) > threshold]def outliers(df: pd.DataFrame, var: str) -> pd.DataFrame:""" Wykrywa odchylenia w zmiennej 'var' przy użyciu metod IQR oraz Z-score. Dla każdej obserwacji ustawia: - Kolumnę 'Odstające_IQR': -1, gdy wartość jest odchyleniem według IQR, inaczej 1. - Kolumnę 'Odstające_Zscore': -1, gdy wartość jest odchyleniem według Z-score, inaczej 1. - Kolumnę 'Czy_Odstające': True, gdy którakolwiek z metod wykryje odchylenie. - Kolumnę 'ile_ident': liczbę metod, które oznaczyły obserwację jako odstającą. Efekt końcowy – wyświetlenie w konsoli tabeli w formacie markdown – zostaje osiągnięty poprzez użycie metody `to_markdown()`. Parametry: df (pd.DataFrame): Ramka danych zawierająca analizowaną zmienną. var (str): Nazwa kolumny, dla której mają być wykrywane odchylenia. Zwraca: pd.DataFrame: Tabela zawierająca tylko te obserwacje, które zostały zakwalifikowane jako odstające. """# Pobierz dane jako jednowymiarowa tablica values = np.array(df[var])# Wykrywanie odchyleń indices_iqr = detect_outliers_iqr(values) indices_zscore = detect_outliers_zscore(values)# Utworzenie ramki danych z oryginalnymi wartościami out_df = pd.DataFrame({var: values}) out_df['Odstające_IQR'] = np.where(out_df.index.isin(indices_iqr), -1, 1) out_df['Odstające_Zscore'] = np.where(out_df.index.isin(indices_zscore), -1, 1) out_df['Czy_Odstające'] = (out_df['Odstające_IQR'] ==-1) | (out_df['Odstające_Zscore'] ==-1)# Wybierz tylko te obserwacje, które są odstające out_df = out_df[out_df['Czy_Odstające']]# Dodaj kolumnę z liczbą metod, które wykryły odchylenie out_df['ile_ident'] = out_df[['Odstające_IQR', 'Odstające_Zscore']].apply(lambda row: (row ==-1).sum(), axis=1)# Wyświetlenie tabeli w formacie markdown display(out_df)return out_dfdisplay(Markdown(f"* Numer wierszy dla których chcemy zmienić wartości na NaN:"))zmienna_liczbowa = ['wiek', 'liczba osób w rodzinie', 'dochody', 'wydatki']for kolumna in zmienna_liczbowa: wynik = outliers(baza, kolumna)ifnot wynik.empty:print(f' zmienna "{kolumna}" zawiera obserwacje nietypowe :') display(Markdown(f"* obserwacje zawiarające wartości odstające liczone wg metod statystycznych IQR oraz Zscore:")) display(wynik)else:print (f' zmienna "{kolumna}" nie zawiera obserwacji nietypowych')display(Markdown(f"* W wyniku analiy ustalono, że w badanym zbiorze brak jest wartości odstających"))
Numer wierszy dla których chcemy zmienić wartości na NaN:
wiek
Odstające_IQR
Odstające_Zscore
Czy_Odstające
ile_ident
zmienna "wiek" nie zawiera obserwacji nietypowych
liczba osób w rodzinie
Odstające_IQR
Odstające_Zscore
Czy_Odstające
ile_ident
zmienna "liczba osób w rodzinie" nie zawiera obserwacji nietypowych
dochody
Odstające_IQR
Odstające_Zscore
Czy_Odstające
ile_ident
zmienna "dochody" nie zawiera obserwacji nietypowych
wydatki
Odstające_IQR
Odstające_Zscore
Czy_Odstające
ile_ident
zmienna "wydatki" nie zawiera obserwacji nietypowych
W wyniku analiy ustalono, że w badanym zbiorze brak jest wartości odstających
3.3. Brakujące dane
3.3.1 Sprawdzenie czy w danych wystepują braki (Null, None) [razem, w wierszach , w kolummnach]
Code
def braki_sprawdzenie(dane):""" Analizuje brakujące dane w tabeli. Parametry: dane (DataFrame): Ramka danych do analizy. Zwraca: None """ liczba = dane.isnull().sum().sum() proc = (liczba / (dane.shape[0]*dane.shape[1])*100).round(2)if liczba ==0:print('Analiza brakujących danych:')print('='*45)print('W tabeli nie stwierdzono brakujących danych!')else:print('Analiza brakujących danych:')print('='*45)print(f'Liczba brakujących danych w tabeli: {liczba}')print(f'Procent brakujących danych w tabeli: {proc}%')print('='*45) rows_with_missing_data = dane[dane.isnull().any(axis=1)] brakujace_dane = rows_with_missing_data.isnull().sum(axis=0) udzial_brakujacych_danych = ((rows_with_missing_data.isnull().sum(axis=0) / dane.shape[0])*100).round(1) wyniki = pd.DataFrame({'liczba': brakujace_dane, 'proc': udzial_brakujacych_danych})print('Brakujące dane w zmiennych (kolumny):') display(wyniki) rows_with_missing_data = dane[dane.isnull().any(axis=1)] brakujace_dane = rows_with_missing_data.isnull().sum(axis=1) udzial_brakujacych_danych = (rows_with_missing_data.isnull().sum(axis=1) / dane.shape[1]*100).round(1) wyniki = pd.DataFrame({'liczba': brakujace_dane, 'proc': udzial_brakujacych_danych})print('='*45)print('Brakujące dane w obserwacjach (wiersze):') display(wyniki)print('='*45) fig, ax = plt.subplots(figsize=(9.5, 4)) sns.heatmap(dane.isnull(), cmap='coolwarm', ax=ax) rows_with_missing_data = dane[dane.isnull().any(axis=1)]print('Tabela z brakującymi danymi:') display(rows_with_missing_data)braki_sprawdzenie(baza)
Analiza brakujących danych:
=============================================
Liczba brakujących danych w tabeli: 21
Procent brakujących danych w tabeli: 1.2%
=============================================
Brakujące dane w zmiennych (kolumny):
liczba
proc
id.
0
0.0
płeć
0
0.0
wykształcenie
3
2.4
wiek
3
2.4
liczba osób w rodzinie
1
0.8
preferowany typ sklepu
2
1.6
preferowana marka sklepu
2
1.6
preferowanay towar
0
0.0
czynnik zakupowy
0
0.0
rodzaj promocji
0
0.0
miasto
0
0.0
liczba ludności
0
0.0
dochody
5
4.0
wydatki
5
4.0
=============================================
Brakujące dane w obserwacjach (wiersze):
liczba
proc
1
2
14.3
2
1
7.1
3
1
7.1
5
2
14.3
6
1
7.1
10
2
14.3
11
1
7.1
39
1
7.1
52
1
7.1
86
2
14.3
103
1
7.1
112
2
14.3
120
2
14.3
126
2
14.3
=============================================
Tabela z brakującymi danymi:
id.
płeć
wykształcenie
wiek
liczba osób w rodzinie
preferowany typ sklepu
preferowana marka sklepu
preferowanay towar
czynnik zakupowy
rodzaj promocji
miasto
liczba ludności
dochody
wydatki
1
R_002
m
podstawowe
16.0
1.0
bazarek
Netto
owoce i warzywa
dostępność
gazetka
Suwałki
69442
NaN
NaN
2
R_003
m
NaN
49.0
1.0
bazarek
Biedronka
produkty piekarnicze
jakość
reklama rtv
Świdnica
60281
50000.0
5160.0
3
R_004
m
podstawowe
NaN
1.0
osiedlowy
Lidl
produkty piekarnicze
jakość
gazetka
Stargard
71464
45000.0
6084.0
5
R_006
m
zawodowe
28.0
1.0
bazarek
Dino
owoce i warzywa
jakość
reklama rtv
Warszawa
1790658
NaN
NaN
6
R_007
m
zawodowe
NaN
5.0
bazarek
Lidl
produkty zbożowe
marka
gazetka
Olsztyn
170904
29000.0
6756.0
10
R_011
m
zawodowe
24.0
3.0
osiedlowy
Kaufland
owoce i warzywa
skład
gazetka
Włocławek
115561
NaN
NaN
11
R_012
m
zawodowe
NaN
5.0
bazarek
Biedronka
napoje
marka
email
Gorzów Wielkopolski
124581
30000.0
9000.0
39
R_040
m
wyższe
69.0
NaN
osiedlowy
Biedronka
napoje
marka
reklama rtv
Piotrków Trybunalski
76279
38000.0
9144.0
52
R_053
k
NaN
21.0
3.0
osiedlowy
Dino
słodycze
jakość
gazetka
Jaworzno
94731
41000.0
9780.0
86
R_078
k
wyższe
25.0
2.0
supermarket
Netto
słodycze
jakość
nie korzystam
Radomsko
49898
NaN
NaN
103
R_095
k
NaN
75.0
4.0
osiedlowy
Biedronka
mięso i wędliny
jakość
reklama rtv
Słupsk
93460
48000.0
11544.0
112
R_104
k
wyższe
77.0
5.0
galeria
Dino
owoce i warzywa
opakowanie
reklama rtv
Nowy Sącz
84270
NaN
NaN
120
R_112
k
wyższe
53.0
5.0
NaN
NaN
słodycze
jakość
nan
Elbląg
119144
54000.0
12936.0
126
R_118
k
wyższe
63.0
2.0
NaN
NaN
produkty zbożowe
jakość
nan
Ełk
60252
57000.0
14964.0
3.3.2. Obsługa brakujących danych (usuwanie [całość, wg progu], imputacja, utworzenie nowej kategorii np. “b.d.”)
W danych znajdują się barkujące dane.Z uwagi na niewielką ilość pozyskanych danych usuwanie takich danych znacznie zmniejszyło by liczbę dostępych danych, dlatego zostanie dokonana imputacja. Natomiast w przypadku wierszy i kolumn , w których znajduje się = >20 % braków o sustaną usuniete, ponieważ tak znaczna ilość braków może nie być losowa, a imputacja mogła by bardzo zniekształcić oryginalny rozkład
Code
baza['dochody'].fillna(baza['dochody'].mean().round(1), inplace=True)baza['wydatki'].fillna(baza['wydatki'].mean().round(1), inplace=True)baza['wiek'].fillna(baza['wiek'].mode()[0], inplace=True)baza['liczba osób w rodzinie'].fillna(baza['liczba osób w rodzinie'].mode()[0], inplace=True)baza['preferowany typ sklepu'].fillna(baza['preferowany typ sklepu'].mode()[0], inplace=True)baza['preferowana marka sklepu'].fillna(baza['preferowana marka sklepu'].mode()[0], inplace=True)baza['wykształcenie'].fillna(baza['wykształcenie'].mode()[0], inplace=True)
Code
braki_sprawdzenie(baza)
Analiza brakujących danych:
=============================================
W tabeli nie stwierdzono brakujących danych!
II. Inżynieria i selekcja cech
4. Wzbogacanie danych
Code
# Tworzenie kategorii wiekubins = [14, 23, 40, 65, 105]labels = ['14-22', '23-39', '40-65', '> 66']baza['wiek_kat'] = pd.cut(baza['wiek'], bins=bins, labels=labels)# Tworzenie kategorii dochodówquantiles = [0, 0.25, 0.5, 0.75, 1]labels = ['niski', 'średni', 'wysoki', 'bardzo wysoki']baza['dochody_kat'] = pd.qcut(baza['dochody'], q=quantiles, labels=labels)# Tworzenie kategorii wydatkówbaza['wydatki_kat'] = pd.qcut(baza['wydatki'], q=quantiles, labels=labels)# Tworzenie kategorii wielkości miastabins = [0, 50000, 200000, 500000, 5000000]labels = ['<50 tys.', '51 tys.-200 tys.', '201 tys.-500 tys.', 'pow 500 tys.']baza['wielkość miasta'] = pd.cut(baza['liczba ludności'], bins=bins, labels=labels)#### 3.4.3. Sprawdzenie czy w zmiennych kategorialnych wystepują obserwacje odstające ( naturalne {obserwacje rzadkie, wysoka kardynalnosć}, błędy)#### 3.4.4. Obsługa obserwacji odstających *(usuwanie, zamiana na NaN, utworzenie nowej kategorii, przypisanie do nowych kategorii zgodnie wiedzą dziedzinową)*# preferowana marka sklepu # rzadkie i wysoka kardynalnosć - zredukować liczbę poziomów utworzyć osobną grupę "inne" z poziomami poniżej 5dict_preferowana_marka_sklepu ={'Aldi':'Inna_lokalna','Dino':'Inna_lokalna','Carrefour':'Inna_lokalna','Polomarket':'Inna_lokalna','Społem':'Inna_lokalna','Intermache':'Inna_lokalna','Groszek':'Inna_lokalna','Jeżyk':'Inna_lokalna','Lewiatan':'Inna_lokalna'}baza['preferowana marka sklepu'] = baza['preferowana marka sklepu'].replace(dict_preferowana_marka_sklepu)dict_rodzaj_promocji ={'inne':'inne','e-mail ':'inne','sms ':'inne','aplikacja ' :'inne','nan ':'inne','sugestia kasjera':'inne'}baza['rodzaj promocji'] = baza['rodzaj promocji'].replace(dict_rodzaj_promocji)czynnik_dict = {'dostępność':'inne','skład':'inne','lokalność':'inne','opinie':'inne','opakowanie':'inne','preferencje kulinarne':'inne'}baza['czynnik zakupowy'] = baza['czynnik zakupowy'].replace(czynnik_dict)zmienna_tekstowa= ['preferowany typ sklepu','preferowana marka sklepu', 'preferowanay towar', 'czynnik zakupowy','rodzaj promocji']for element in zmienna_tekstowa: display(baza[element].value_counts(normalize=True)*100)
czynnik zakupowy
jakość 37.6
cena 30.4
marka 16.8
inne 15.2
Name: proportion, dtype: float64
rodzaj promocji
gazetka 36.0
reklama rtv 27.2
nie korzystam 15.2
karta 11.2
inne 8.0
email 2.4
Name: proportion, dtype: float64
Code
zmienna= ['wiek_kat', 'dochody_kat', 'wydatki_kat', 'wielkość miasta']for element in zmienna: display(baza[element].value_counts(normalize=True).round(2)*100)